#include "Condors.h"

/**
*@author Eduardo Pereyra, Tomas Anton Lopetegui
*/


/**
* sem_post desbloquea el semaforo
* sem_wait bloquea el semaforo
*/


sem_t sem_despertar,sem_start,sem_dormida,sem_potes,sem_end;
pthread_t *tid_condors;
pote *potes;
int idBebeDespertador    = 0;
int deVacaciones = FALSE;


/**
* verifica que todos los potes esten vacios
*/
int hayComida(){
    int i;
    int hayComida = FALSE;
    for(i = 0;i<CNT_POTES;i++){
        if(potes[i].comida > 0){
            hayComida = TRUE;
        }
    }
    return hayComida;
}

void mostrarPotes(){
    int i;

    for(i = 0;i<CNT_POTES;i++){
        printf("Pote [%d] : %d\n", i, potes[i].comida);
    }
}


int listo_para_comer(int id_bebe) {
    int i = 0;
    sem_wait(&sem_potes);

    for (i = 0; i < CNT_POTES; i++) {
        if (sem_trywait(&potes[i].sem_pote) != -1) {
            if (potes[i].comida == 0){
                sem_post(&potes[i].sem_pote);
            }
            else {
                return i;
            }
        }
    }

    /** Mama no esta y no hay mas comida, se liberan los potes y
    * se cierra el thread
    */
    if (deVacaciones) {
        printf("No hay mas comida y mama se fue\n");
        sem_post(&sem_potes);
        pthread_exit(0);
    }

    if (hayComida() == 0) {
        if(sem_trywait(&sem_despertar) != -1 ){
        printf("\nPOTES VACIOS!!!\n");
        mostrarPotes();
        printf("\nBebe condor %d ve que todos los potes estan vacios y despierta a mama\n", id_bebe);
        idBebeDespertador = id_bebe;
        sem_post(&sem_dormida); //libero semaforo para poder despertar a mama
        }
    }
    sem_post(&sem_potes); // Libero los potes

    return listo_para_comer(id_bebe);
}


void terminar_de_comer(int id_bebe, int pote) {
    int cnt_comida;
    if (potes[pote].comida <= 5){
         cnt_comida = potes[pote].comida;
    }
    else {
        cnt_comida = rand() % 5;
        if (cnt_comida == 0) cnt_comida = 1;
    }


    printf("Bebe condor %d come [%d] - %d\n", id_bebe, pote,potes[pote].comida);

    potes[pote].comida = potes[pote].comida - cnt_comida;
    sem_post(&potes[pote].sem_pote);
    sem_post(&sem_potes);
}


void ira_dormir(void) {
    printf("Mama condor duerme la siesta\n");
    sem_wait(&sem_dormida);
}

void comida_lista(ronda) {
    int i;

    printf("\nMama condor dice Ronda (%d) \n", ronda);
    for (i = 0; i < CNT_POTES; i++){
         potes[i].comida = CNT_LLENO_POTE;
    }
    sem_post(&sem_despertar);
}

void *ThreadMamaCondor(int *param) {
    int ronda = 0;

    sem_wait(&sem_start);
    sem_post(&sem_start);

    printf("Comienza Mama condor\n");

    while (!deVacaciones) {
        ira_dormir();
        printf("\nMama condor esta despierta por bebe condor %d y comienza la caza de la comida\n",
               idBebeDespertador);
        Sleep(rand() % 500);
        ronda++;
        comida_lista(ronda);
        if (ronda == CNT_RONDAS){
             deVacaciones = TRUE;
        }
        Sleep(rand() % 50); // hacer otras cosas
    }
    printf("\n\nMe voy de vacaciones\n");
    printf("Mama condor se va de vacaciones luego de las %d rondas de alimentacion\n", CNT_RONDAS);
    sem_post(&sem_end);
    return (void *)1;
}
void *ThreadCondor(int id_bebe) {
    int pote_a_usar = 0;

    id_bebe++;

    sem_wait(&sem_start);
    sem_post(&sem_start);

    printf("Comienza el bebe condor %d\n", id_bebe);

    while (!deVacaciones) {
        Sleep(rand() % 10000); //bebe condor juega
        printf("Bebe condor %d esta listo para comer\n", id_bebe);
        pote_a_usar = listo_para_comer(id_bebe); //obtener pote disponible
        Sleep(rand() % 10000); // bebe condor come
        terminar_de_comer(id_bebe, pote_a_usar);
        printf("Bebe condor %d termino de comer.\n", id_bebe);
    }

    return (void *)1;
}

int main(int argc, char * argv[]) {
    int i = 0;

    /**
    * Asignacion de memoria
    */

    size_t len_condors, len_potes;

    srand(getpid());

    len_condors = sizeof(pthread_t) * CNT_CONDORS;
    len_potes   = sizeof(pote) * CNT_POTES;

    tid_condors = (pthread_t *) malloc(len_condors);
    potes = (pote *) malloc(len_potes);

    memset(tid_condors, 0, len_condors);
    memset(potes, 0, len_potes);

    /**
    * Fin Asignacion de memoria
    */

    sem_init(&sem_start, 0, 1);
    sem_wait(&sem_start);

    sem_init(&sem_end, 0, 1);
    sem_wait(&sem_end);

    for (i = 0; i < CNT_POTES; i++) {
        sem_init(&potes[i].sem_pote, 0, 1);
    }

    sem_init(&sem_despertar, 0, 1);

    sem_init(&sem_dormida, 0, 1);
    sem_wait(&sem_dormida); // Mama condor empieza dormida

    sem_init(&sem_potes, 0, CNT_POTES);


    printf("Hay %d bebes condor, %d potes de comida y %d rondas de alimentacion\n", \
           CNT_CONDORS, CNT_POTES, CNT_RONDAS);

    if(pthread_create(&tid_condors[i], NULL, (void *) ThreadMamaCondor, NULL)) {
        printf("\n **Error al crear condor: [%d]**\n", i);
        exit(1);
    }


    for (i = 0; i < CNT_CONDORS; i++) {
        if(pthread_create(&tid_condors[i], NULL, (void *) ThreadCondor, i)) {
            printf("\n **Error al crear condor: [%d]**\n", i);
            exit(1);
        }
    }
    printf("Comienza el juego\n\n");
    sem_post(&sem_start);

    sem_wait(&sem_end);

    // Espero que todos los treads terminen su ejecucion
    for (i = 0; i < CNT_CONDORS; i++){
         pthread_join(tid_condors[i], NULL);
    }
    mostrarPotes();
    printf("Termina el juego\n");

    return 1;
}



